package org.fle4y.app.server.database;

import java.sql.SQLException;
import java.util.Vector;

/**
 * author : xiehui<br>
 * company : northking <br>
 * Create at: 2012-6-15<br>
 * 
 * @version : 1.0<br>
 *          mailto:flexie@foxmail.com<br>
 *          Description : 数据库实体
 */
public class Database {
	private Vector<Table> tables;

	public Database() {
		tables = new Vector<Table>();
	}

	public synchronized Result execute(String sql) {
		Result result = new Result();
		Tokenizer tokenizer = new Tokenizer(sql);
		Parser parser = new Parser(this, tokenizer);
		try {
			while (true) {
				int begin = tokenizer.getPosition();
				String token = tokenizer.getString();
				if (token.equals("")) {
					break;
				} else if (token.equals("SELECT")) {

				} else if (token.equals("CREATE")) {
					result = processCreate(tokenizer);
				}
			}
		} catch (SQLException e) {
			e.printStackTrace();
			result = new Result("错误的语句 ! ");
		}
		return result;
	}

	private Result processCreate(Tokenizer tokenizer) throws SQLException {
		String token = tokenizer.getString();
		if ("TABLE".equals(token)) {
			processCreateTable(tokenizer);
		}
		return null;
	}

	private void processCreateTable(Tokenizer tokenizer) throws SQLException {
		Table t;
		String token = tokenizer.getName();
		t = new Table(this, token);
		tokenizer.getThis("(");

		int primarykeycolumn = -1;
		int column = 0;
		boolean constraint = false;
		while (true) {
			token = tokenizer.getString();
			if (token.equals("CONSTRAINT") || token.equals("PRIMARY")
					|| token.equals("FOREIGN") || token.equals("UNIQUE")) {
				tokenizer.back();
				constraint = true;
				break;
			}
			String columnName = token;
			int type = Column.getTypeNr(tokenizer.getString());
			token = tokenizer.getString();

			/** 处理浮点型,目前没有实现处理浮点型的长度 */
			if ("(".equals(token)) {
				do {
					token = tokenizer.getString();
				} while (!")".equals(token));
				token = tokenizer.getString();
			}

			/** 处理非空约束 */
			boolean nullable = true;
			if ("NULL".equals(token)) {
				token = tokenizer.getString();
			} else if ("NOT".equals(token)) {
				tokenizer.getThis("NULL");
				nullable = false;
				token = tokenizer.getString();
			}

			/** 处理主键 */
			if ("PRIMARY".equals(token)) {
				tokenizer.getThis("KEY");
				if (primarykeycolumn != -1) {
					throw new SQLException("一张表中不能定义两个主键！");
				}
				primarykeycolumn = column;
				token = tokenizer.getString();
			}

			/** 解析出一个字段,保存 */
			t.addColumn(columnName, type, nullable);

			if (")".equals(token)) {
				break;
			}
			if (!",".equals(token)) {
				throw new SQLException("错误的SQL语句,缺少字符 , !");
			}

			column++;
		}

		/** 所有字段解析完成后,处理主键约束 */
		if (primarykeycolumn != -1) {
			t.createPrimaryKey(primarykeycolumn);
		} else {
			/** 如果没有主键,我们自动生成一个隐藏主键 */
			t.createPrimaryKey();
		}

		/** 处理其他约束 */
		if (constraint) {
			int i = 0;
			while (true) {
				token = tokenizer.getString();
				String name = "SYSTEM_CONSTRAINT_" + i;
				i++;
				if (token.equals("CONSTRAINT")) {
					name = tokenizer.getString();
					token = tokenizer.getString();
				}
				if (token.equals("PRIMARY")) {
					tokenizer.getThis("KEY");
					addUniqueConstraintOn(tokenizer, name, t);
				} else if (token.equals("UNIQUE")) {
					addUniqueConstraintOn(tokenizer, name, t);
				} else if (token.equals("FOREIGN")) {
					tokenizer.getThis("KEY");
					addForeignKeyOn(tokenizer, name, t);
				}
				token = tokenizer.getString();
				if (token.equals(")")) {
					break;
				}
				if (!token.equals(",")) {
					throw new SQLException("错误的结尾字符 ！");
				}
			}
		}
		linkTable(t);
	}

	public void addUniqueConstraintOn(Tokenizer c, String name, Table t)
			throws SQLException {
		int col[] = processColumnList(c, t);
		createIndex(t, col, name, true);
		t.addConstraint(new Constraint(Constraint.UNIQUE, t, col));
	}

	public int[] processColumnList(Tokenizer c, Table t) throws SQLException {
		Vector<String> v = new Vector<String>();
		c.getThis("(");
		while (true) {
			v.addElement(c.getString());
			String sToken = c.getString();
			if (sToken.equals(")")) {
				break;
			}
			if (!sToken.equals(",")) {
				throw new SQLException("未知的字符 ！");
			}
		}
		int s = v.size();
		int col[] = new int[s];
		for (int i = 0; i < s; i++) {
			col[i] = t.getColumnNr((String) v.elementAt(i));
		}
		return col;
	}

	public void addForeignKeyOn(Tokenizer c, String name, Table t)
			throws SQLException {
		int col[] = processColumnList(c, t);
		c.getThis("REFERENCES");
		Table t2 = getTable(c.getString());
		int col2[] = processColumnList(c, t2);
		if (t.getIndexForColumns(col) == null) {
			createIndex(t, col, "SYSTEM_FOREIGN_KEY_" + name, false);
		}
		if (t2.getIndexForColumns(col2) == null) {
			createIndex(t2, col2, "SYSTEM_REFERENCE_" + name, false);
		}
		t.addConstraint(new Constraint(Constraint.FOREIGN_KEY, t2, t,
						col2, col));
		t2.addConstraint(new Constraint(Constraint.MAIN, t2, t, col2, col));
	}

	public void createIndex(Table t, int col[], String name, boolean unique)
			throws SQLException {
		if (t.isEmpty()) {
			t.createIndex(col, name, unique);
		}
	}

	public Table getTable(String name) throws SQLException {
		Table t = null;
		for (int i = 0; i < tables.size(); i++) {
			t = tables.elementAt(i);
			if (t.getName().equals(name)) {
				return t;
			}
		}
		if (t == null) {
			throw new SQLException("表没有找到 ！");
		}
		return t;
	}

	public void linkTable(Table t) throws SQLException {
		String name = t.getName();
		for (int i = 0; i < tables.size(); i++) {
			Table o = tables.elementAt(i);
			if (o.getName().equals(name)) {
				throw new SQLException("表已经存在 !");
			}
		}
		tables.addElement(t);
	}

}
